﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Diagnostics;

class Program
{
    static void Main(string[] args)
    {
        Dictionary<int, string> ByteSuffix = new Dictionary<int, string>()
        {
            {0, "B"},
            {1, "KB"},
            {2, "MB"},
            {3, "GB"}
        };
        string dir = "";
        string Suffix = "";
        long TotalSizeOfFiles = 0;
        long TotalWastedSpace = 0;
        int divisor = 0;
        
        //Starting Directory
        if (args.Length > 0)
        {
            dir = args[0];
        }
        else
        {
            dir = ".";
        }

        Process p = Process.GetCurrentProcess();
        ToolKit._AppLog = p.ProcessName + ".log";

        //ToolKit._AppLog = @".\GITSUM.log";

        ToolKit.LogIt("Begin.");
        ToolKit.LogIt();

        ToolKit.LogIt("Directory searched: ", dir);
        // Declare ArrayList that will contain a list of CheckSum objects.
        //
        // The idea is put all of the files with matching checksum values in the same list
        // NOTE:  A list of CheckSum objects. One of the data members of the CheckSum class is
        //        a list of filenames.
        ArrayList CheckSumList = new ArrayList();

        // Get all files in current directory
        foreach (string file in Directory.GetFiles(dir))
        {
            // Add file to list of CheckSums
            if (!ToolKit.FileInUse(file)) UserClass.AddFile(file, ref CheckSumList);
        }

        // Search subdirectories
        ToolKit.DirSearch(dir, ref CheckSumList);

        //Display CheckSum Results
        if (CheckSumList != null)
        {
            // CheckSumList is an ArrayList of CheckSum objects
            // ...foreach CheckSum object do...
            foreach (FileCheckSum F in CheckSumList)
            {
                divisor = ToolKit.CalcDivisor((long) F.FileSize);
                ByteSuffix.TryGetValue(divisor, out Suffix);
                // Write out the data members of each CheckSum object
                ToolKit.LogIt("Summary for Checksum:", F.CheckSum);
                ToolKit.LogIt("-----------------------------------------");
                ToolKit.LogIt("Size of all files: ", ((F.FileSize * F.Files.Count) / (Math.Pow(1024, divisor))), Suffix);
                ToolKit.LogIt(" Size of one file: ", (F.FileSize/(Math.Pow(1024, divisor))), Suffix);
                ToolKit.LogIt("Wasted disk space: ", (((F.FileSize * F.Files.Count) - F.FileSize)/(Math.Pow(1024, divisor))), Suffix);
                ToolKit.LogIt("-----------------------------------------");
                
                // One of the data members of each CheckSum object is an ArrayList of file names...
                // ...Write out each file name...
                foreach (string FileName in F.Files)
                {
                    ToolKit.LogIt("FileNames: ", FileName);
                }
                ToolKit.LogIt();
                TotalSizeOfFiles = TotalSizeOfFiles + ( (long)F.FileSize * F.Files.Count);
                TotalWastedSpace = TotalWastedSpace + (((long)F.FileSize * F.Files.Count) - (long) F.FileSize);
            }

            divisor = ToolKit.CalcDivisor(TotalSizeOfFiles);
            ByteSuffix.TryGetValue(divisor, out Suffix);
            ToolKit.LogIt("Summary for All Files:");
            ToolKit.LogIt("-----------------------------------------");
            ToolKit.LogIt("           Size of all files: ", (TotalSizeOfFiles / (Math.Pow(1024, divisor))), Suffix);
            ToolKit.LogIt("Size of Non-Duplicated Files: ", ((TotalSizeOfFiles-TotalWastedSpace)/(Math.Pow(1024, divisor))), Suffix);
            ToolKit.LogIt("     Total Wasted disk space: ", (TotalWastedSpace/(Math.Pow(1024, divisor))), Suffix);
            ToolKit.LogIt("-----------------------------------------");
        }
        ToolKit.LogIt("End.\n");
    }
}

//  Class Created for keeping track of checksums.
//  Files data member is a list of all files that have checksums that
//  match PrimaryCheckSum and SecondaryCheckSum data members
class FileCheckSum 
{
    public UInt64 CheckSum;
    public double FileSize;
    public ArrayList Files = new ArrayList();

    // Constructor
    public FileCheckSum(string file)
    {
        // Get File Size from FileInfo assign it to CheckSum.FileSize data member
        FileInfo f = new FileInfo(file);
        FileSize = f.Length;
        CheckSum = ToolKit.CalCheckSum(file);
        
        Files.Add(file);
    }
}

// UserClass and AddFile method are called by ToolKit.DirSearch
// Effectively, ToolKit.Direarch (recursive search) can be used with any program.  The program must have
// UserClass.AddFile class and then modifications to ToolKit.DirSearch will not be required...
// UserClass.AddFile can be written to do anything with the file and Arraylist reference passed.
class UserClass
{
    public static void AddFile(string file, ref ArrayList CSL)
    {

        FileCheckSum FIQ = new FileCheckSum(file);
        // Search through the list of CheckSum objects to see if there is a
        // CheckSum object that has a matching PrimaryCheckSum and SecondaryCheckSum
        // if so add the filename to the from FIQ object to the existing CheckSum object.
        foreach (FileCheckSum Value in CSL)
        {
            if ( (Value.CheckSum == FIQ.CheckSum)
               )
            {
                Value.Files.Add(FIQ.Files[0]);
                FIQ = null;
                return;
            }
        }

        // No existing CheckSum object matches the FIQ
        CSL.Add(FIQ);
        FIQ = null;
        return;
    }
}